﻿package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	
	public class MultiSpring extends Sprite
	{
		private var ball:Ball;
		public var ballMass:Number;
		
		public var bar:Bar;
		public var barX:Number;
		public var barY:Number;
		public var barRot:Number;
		public var barLength:Number;
		public var barHeight:Number;
		public var barMass:Number;
		
		public var point:Ball; //The fixed point
		
		private var spring:Number;
		private var friction:Number;
		private var springLength:Number;
		
		private var gravity:Number = 0.6;
		private var bounce:Number = -0.9;
				
		public function MultiSpring()
		{
			spring = 0.1;
			friction = 0.8;
			springLength = 50;
			
			barX = 100;
			barY = 350;			
			barRot = 0;
			barLength = 300;
			barHeight = 5;
			barMass = 200;
			
			ball = new Ball(20);
			ballMass = 100;
			addChild(ball);
			ball.x = 250;
			ball.y = 50;
			
			init();
		}
		
		private function init():void
		{		
			bar = new Bar(barX, barY, barRot);
			bar.x = barX;
			bar.y = barY;
			addChild(bar);
			
			point = new Ball(10, 0x0000ff);			
			point.x = 400;
			point.y = 400;			
			addChild(point);		
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);			
		}
		
		private function onEnterFrame(event:Event):void
		{				
			//Move the ball
			moveBall(ball);
			
			//Bounce off ceiling, floor and walls
			checkSides(ball);
			
			//Check collisions with the bar		
			checkLine(bar);			
			
			//Adjust the spring
			springTo(bar, point);		
		}
		
		private function moveBall(ball):void
		{
			ball.vy += gravity;
			ball.x += ball.vx;
			ball.y += ball.vy;
		}
		
		private function springTo(bar:Bar, point:Ball):void
		{
			//var springPointX = (barLength * Math.cos(bar.rotation)) + bar.x;
			//var springPointY = (barLength * Math.sin(bar.rotation)) + bar.y;			
			// trace(bar.rotation);
			var springPointX = bar.x + barLength;
			var springPointY = bar.y + barHeight;
			
			var dx:Number = point.x - springPointX;
			var dy:Number = point.y - springPointY;
			var angle:Number = Math.atan2(dy, dx);
			var targetX:Number = point.x - Math.cos(angle) * springLength;
			var targetY:Number = point.y - Math.sin(angle) * springLength;
			bar.vx += (targetX - springPointX) * spring;
			bar.vy += (targetY - springPointY) * spring;
			bar.vx *= friction;
			bar.vy *= friction;
			bar.x += bar.vx;
			bar.y += bar.vy;
			
			graphics.clear();
			graphics.lineStyle(1);
			
			graphics.moveTo(bar.x + barLength, bar.y + barHeight);
			graphics.lineTo(point.x, point.y);	
		}
		
		public function checkSides(ball:Ball):void
		{
			if(ball.x + ball.radius > stage.stageWidth)
			{
				ball.x = stage.stageWidth - ball.radius;
				ball.vx *= bounce;
			}
			else if(ball.x - ball.radius < 0)
			{
				ball.x = ball.radius;
				ball.vx *= bounce;
			}
			if(ball.y + ball.radius > stage.stageHeight)
			{
				ball.y = stage.stageHeight - ball.radius;
				ball.vy *= bounce;
			}
			else if(ball.y - ball.radius < 0)
			{
				ball.y = ball.radius;
				ball.vy *= bounce;
			}
		}
		
		//Based on David Schwartz's Linear Collision class
		private function checkLine(bar:Bar):void
		{			
			var bounds:Rectangle = new Rectangle(bar.x, bar.y, 300, 10);			
			
			if(ball.x >= bounds.left && ball.x <= bounds.right)
			{				
				// get angle, sine and cosine
				var angle:Number = bar.rotation * Math.PI / 180;
				var cos:Number = Math.cos(angle);
				var sin:Number = Math.sin(angle);
				
				// get position of ball, relative to line
				var x1:Number = ball.x - bar.x;
				var y1:Number = ball.y - bar.y;
				
				// rotate coordinates
				var y2:Number = cos * y1 - sin * x1;
				
				// rotate velocity
				var vy1:Number = cos * ball.vy - sin * ball.vx;
				
				// perform bounce with rotated values
				if(y2 > -ball.height / 2 && y2 < vy1)
				{
					// rotate coordinates
					var x2:Number = cos * x1 + sin * y1;
					
					// rotate velocity
					var vx1:Number = cos * ball.vx + sin * ball.vy;
					
					if(y2 > -ball.height / 2 && y2 < vy1)
					{
						y2 = -ball.height / 2;
						vy1 *= bounce;
					}
					
					// rotate everything back;
					x1 = cos * x2 - sin * y2;
					y1 = cos * y2 + sin * x2;
					
					ball.vx = cos * vx1 - sin * vy1;
					ball.vy = cos * vy1 + sin * vx1;
					
					ball.x = bar.x + x1;
					ball.y = bar.y + y1;
					
					//Rotate once hit
					bar.rotation += 1;
					
					//Inertia (Faked...?)					
					bar.y -= (ballMass/barMass) * ball.vy;
				}
			}
		}	
	}
}
